﻿using Newtonsoft.Json.Linq;
using OpenTK.Mathematics;
using spriteeditor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Xml.Linq;
using ttbit.core;
using static OpenTK.Graphics.OpenGL.GL;


namespace ttbit.WorkingSpace
{

    /// <summary>
    /// Parser 负责资源的读写
    /// </summary>
    public interface IWorkResourceParser
    {
        /// <summary>
        /// 哪些扩展名的文件 会标记为这个资源，可以重复，重复扩展名可以选 比如PNG 可以是一个Sprite 也可以是一个 Texture
        /// </summary>
        string[] FileExt
        {
            get;
        }

        /// <summary>
        /// 该资源的描述
        /// </summary>
        string TypeName
        {
            get;
        }
        /// <summary>
        /// 可否直接创建这个资源，有些资源是锁定具体文件的，就不能直接Create，必须有文件在
        /// </summary>
        bool CanCreate
        {
            get;
        }
        IWorkResource Load(bool reimport, System.IO.Stream metaStream, string path);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="resource"></param>
        /// <param name="metaStream"></param>
        /// <param name="path"></param>
        /// <returns>Data是否写入，如果Data发生了写入，meta头就会改变</returns>
        bool Save(IWorkResource resource, System.IO.Stream metaStream, string path);

    }
    /// <summary>
    /// Editor 负责资源的编辑
    /// </summary>




    //什么文件监视啦，以后再说
    public class WorkingSpace : IResDataSource
    {
        public EditorApp editorapp
        {
            get;
            private set;
        }
        public WorkingSpace(EditorApp app)
        {
            WorkingPath = null;
            this.editorapp = app;
        }
        const string workspacefile = "ttbit.config.json";
        public bool IsOpen
        {
            get
            {
                return WorkingPath != null;
            }
        }
        public string WorkingPath
        {
            get;
            private set;
        }
        Dictionary<string, string> allFiles;
        Dictionary<string, MetaInfo> allMeta;
        public string[] GetAllResourceNames()
        {
            return allFiles.Keys.ToArray();
        }

        public bool GetResourceInfo(string name, out string path, out MetaInfo meta)
        {
            var b = allFiles.TryGetValue(name.ToLower(), out path);
            if (!b)
            {
                path = null;
            }
            var b2 = allMeta.TryGetValue(name.ToLower(), out meta);
            if (!b2)
            {
                meta = null;
            }
            return b && b2;
        }
        public void Save(IWorkResource resource, string type, FileInfo fileinfo)
        {
            var name = System.IO.Path.GetFileNameWithoutExtension(fileinfo.Name).ToLower();
            var parser = editorapp.resmgr.GetParser(type);
            if (parser != null)
            {
                MetaInfo meta = new MetaInfo();
                using (var metafs = System.IO.File.OpenWrite(fileinfo.FullName + ".meta"))
                {
                    metafs.Position = 96;
                    parser.Save(resource, metafs, fileinfo.FullName);
                    meta.Init(type, fileinfo);

                    metafs.Position = 0;
                    meta.Write(metafs);
                }
                resource.ClearDirty();

                allMeta[name.ToLower()] = meta;
            }
        }
        public void ReImport(string type, FileInfo fileinfo)
        {
            //var name = System.IO.Path.GetFileNameWithoutExtension(fileinfo.Name).ToLower();
            var parser = editorapp.resmgr.GetParser(type);
            if (parser != null)
            {
                var res = parser.Load(true, null, fileinfo.FullName);
                Save(res, type, fileinfo);
                //MetaInfo meta = new MetaInfo();
                //using (var metafs = System.IO.File.OpenWrite(fileinfo.FullName + ".meta"))
                //{
                //    metafs.Position = 96;
                //    var bupdate = parser.Save(res, metafs, fileinfo.FullName);
                   
                //    meta.Init(type, fileinfo);

                //    //啥都不管，直接重新写入meta并更换meta
                //    metafs.Position = 0;
                //    meta.Write(metafs);
                //}
                //allMeta[name.ToLower()] = meta;
                res.Dispose();
            }
            else
            {
                throw new Exception("no parser:" + type);
            }
        }
        public void RefreshAll()
        {
            var file = System.IO.Directory.GetFiles(WorkingPath, "*.*", SearchOption.AllDirectories);
            allFiles = new Dictionary<string, string>();
            allMeta = new Dictionary<string, MetaInfo>();
            foreach (var f in file)
            {
                var ext = System.IO.Path.GetExtension(f).ToLower();
                if (ext == ".meta" || ext == ".meta2")//忽略meta文件 //meta 第一行固定 96字节
                                                      //Magic 4字节 +空格+Type 16字节 +空格 + 8字节 hexstr srcsize+ 空格+ 64字节hexstr srchash + 回车
                                                      //4+1+16+1 + 8+1 +64+1 = 96字节
                                                      //之后的数据自定义
                                                      //如果用户觉得一个文件不够，还可以启用meta2
                {
                    continue;
                }

                var name = System.IO.Path.GetFileNameWithoutExtension(f).ToLower();
                if (name == "ttbit.config")
                    continue;

                if (allFiles.ContainsKey(name))
                {
                    //重复文件错误
                    break;
                }
                allFiles[name] = f;
                if (System.IO.File.Exists(f + ".meta"))//有Meta 加载Meta
                {
                    try
                    {
                        var meta = new MetaInfo();
                        var bmetachange = meta.LoadAndCheck(new FileInfo(f));

                        //string metatype = null;
                        //byte[] info = new byte[95];
                        //using (var fs = System.IO.File.OpenRead(f + ".meta"))
                        //{
                        //    fs.Read(info, 0, 95);
                        //    string head = System.Text.Encoding.ASCII.GetString(info);
                        //    var works = head.Split(' ', StringSplitOptions.RemoveEmptyEntries);

                        //    metatype = works[1];

                        //    var filesize = BitConverter.ToUInt32(Convert.FromHexString(works[2]));

                        //    var srcfilehash = Convert.FromHexString(works[3]);

                        //}
                        //var meta = new MetaInfo();
                        //meta.LoadAndCheck(metatype,)
                        var parser = editorapp.resmgr.GetParser(meta.Type);

                        using var fsmeta = System.IO.File.Open(f + ".meta", FileMode.Open, FileAccess.ReadWrite);

                        if (bmetachange)
                        {
                            fsmeta.Position = 96;
                            var res = parser.Load(bmetachange, fsmeta, f);
                            fsmeta.Position = 96;
                            var bdatachange = parser.Save(res, fsmeta, f);
                            res.Dispose();

                            if (bdatachange)
                            {
                                meta.Init(meta.Type, new FileInfo(f));
                                fsmeta.Position = 0;
                                meta.Write(fsmeta);
                            }

                        }
                        allMeta[name] = meta;
                    }
                    catch(Exception err)
                    {
                        continue;
                    }
   
                }
                else
                {
                    var parser = editorapp.resmgr.GetFirstParserByExt(ext);
                    if (parser != null)
                    {
                        var meta = new MetaInfo();
                        meta.Init(parser.TypeName, new FileInfo(f));

                       

                        var res = parser.Load(true, null, f);

                        using var fsmeta = System.IO.File.OpenWrite(f + ".meta");
                        fsmeta.Position = 96;
                        var bdatachange = parser.Save(res, fsmeta, f);
                        res.Dispose();


                        fsmeta.Position = 0;
                        {
                            meta.Init(meta.Type, new FileInfo(f));
                            fsmeta.Position = 0;
                            meta.Write(fsmeta);
                        }

                        allMeta[name.ToLower()] = meta;

                    }
                    else
                    {
                        continue;
                    }
                }

            }
        }

        //刷新所有资源
        public void Refresh()
        {

        }
        public void Close()
        {
            WorkingPath = null;
            this.allFiles.Clear();
            this.allMeta.Clear();
            editorapp.logger.Log("WorkSpace Close." );
            editorapp.resmgr.CloseAll();
        }
        public string[] historypath
        {
            get;
            private set;
        }
        public void InitHistory()
        {

            try
            {
                historypath = System.IO.File.ReadAllLines("history.txt");
            }
            catch
            {
                historypath = new string[0];
            }
        }
        public void SaveHistory()
        {
            System.IO.File.WriteAllLines("history.txt", historypath);
        }
        public bool New(string path)
        {
            var file = System.IO.Path.Combine(path, workspacefile);
            if (File.Exists(file))
                return false;
            JObject json = new JObject();
            json["ver"] = "ttbit v0.1";
            System.IO.File.WriteAllText(file, json.ToString());
            WorkingPath = path;

            RefreshAll();
            if (historypath != null && historypath.Contains(path) == false)
            {
                List<string> list = new List<string>(historypath);
                list.Insert(0, path);
                while (list.Count > 10)
                    list.RemoveAt(10);
                historypath = list.ToArray();
                SaveHistory();
            }

            return true;
        }
        public bool Open(string path)
        {
            var file = System.IO.Path.Combine(path, workspacefile);
            if (!File.Exists(file))
                return false;

            WorkingPath = path;

            RefreshAll();
            if (historypath != null && historypath.Contains(path) == false)
            {
                List<string> list = new List<string>(historypath);
                list.Insert(0, path);
                while (list.Count > 10)
                    list.RemoveAt(10);
                historypath = list.ToArray();
                SaveHistory();
            }
            editorapp.logger.Log("WorkSpace Open:" + path);
            return true;

        }


        /// <summary>
        /// 从这往下的东西，都不要
        /// </summary>
        /// <param name="name"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        //public byte[] LoadRGBA(string name, out int width, out int height)
        //{
        //    var lname = name.ToLower();

        //    string realfile = null;
        //    if (shorttexname.TryGetValue(lname, out var texfilename))
        //    {
        //        realfile = texfilename;
        //    }
        //    if (packtexname.TryGetValue(lname, out var packfilename))
        //    {
        //        realfile = packfilename;
        //    }
        //    if (newtexname.TryGetValue(lname, out var newfilename))
        //    {
        //        realfile = newfilename;
        //    }
        //    if (realfile != null)
        //    {
        //        using (var fs = System.IO.File.OpenRead(realfile))
        //        {
        //            var t = CoreLoadTool.LoadTextureData_RGBA(fs, out width, out height);

        //            return t;
        //        }
        //    }
        //    width = 0;
        //    height = 0;
        //    return null;
        //}
        //public Texture GetTexture(string name)
        //{
        //    var lname = name.ToLower();
        //    if (realTextures.TryGetValue(lname, out var tex))
        //    {
        //        return tex;
        //    }
        //    string realfile = null;
        //    if (shorttexname.TryGetValue(lname, out var texfilename))
        //    {
        //        realfile = texfilename;
        //    }
        //    if (packtexname.TryGetValue(lname, out var packfilename))
        //    {
        //        realfile = packfilename;
        //    }
        //    if (newtexname.TryGetValue(lname, out var newfilename))
        //    {
        //        realfile = newfilename;
        //    }
        //    if (realfile != null)
        //    {
        //        using (var fs = System.IO.File.OpenRead(realfile))
        //        {
        //            var t = CoreLoadTool.LoadTextureData_RGBA(fs, out int w, out int h);
        //            var ntex = new Texture((ushort)w, (ushort)h, ttbit.IGL.TextureType.RGBA_32, t);
        //            realTextures[lname] = ntex;
        //            return ntex;
        //        }
        //    }

        //    return null;
        //}
        //public Dictionary<string, string> shorttexname;
        //public Dictionary<string, string> packtexname;
        //public Dictionary<string, string> newtexname;


        //Dictionary<string, Texture> realTextures;
        //public PlayerList playerList;
        //public SpriteList spriteList;


        //public int usermode;//mode1 showsprite
        //public List<SkinSprite> usermode_showlist;
        //public float usermode_scale = 1.0f;
        //public bool usermode_crossfront = false;
        //public NodeTag_Sprite usermode_editsprite = null;
        //public void ConvertWildTex2Sprite(string name, string playername, string partname)
        //{
        //    if (!this.newtexname.Remove(name, out string _filename))
        //    {
        //        MessageBox.Show("error no tex:" + name);
        //        return;
        //    }
        //    this.shorttexname[name] = _filename;
        //    var skinSprite = new SkinSprite();
        //    skinSprite.name = System.IO.Path.GetFileNameWithoutExtension(name);
        //    skinSprite.filename = name;
        //    skinSprite.playername = playername;
        //    skinSprite.part_name = partname;
        //    skinSprite.part_skin = "";
        //    skinSprite.part_id = "";//autogen
        //    skinSprite.povit = Point.Empty;
        //    var texdata = this.LoadRGBA(name, out int w, out int h);
        //    GetBorder(texdata, w, h, out var x, out var y, out var x2, out var y2);
        //    skinSprite.uv = new Rectangle(x, y, x2 - x + 1, y2 - y + 1);
        //    skinSprite.povit.X = (x2 - x) / 2;
        //    skinSprite.povit.Y = (y2 - y) * 3 / 4;
        //    this.spriteList.Sprites.Add(skinSprite);

        //}



    }
    public class SkinSprite
    {

        public string name;     //精灵名
        public string filename; //精灵所在的文件名

        public string resgroup; //打包的时候分到哪个贴图里

        public string playername;   //归属于哪个角色，也可以不归属
        public string part_name;    //兼容部位名，换装用
        public string part_skin;    //换装皮肤名
        public string part_id;      //部位id，换装用

        public Rectangle uv;    //UV
        public Point povit;//轴  //轴
    }
    public class SpriteList
    {
        public List<SkinSprite> Sprites = new List<SkinSprite>();
        public void LoadFromJson(JArray json)
        {
            Sprites = new List<SkinSprite>();
            foreach (JObject item in json)
            {
                SkinSprite s = new SkinSprite();
                s.filename = item["filename"].ToString();
                s.name = item["name"].ToString();
                if (item.ContainsKey("resgroup"))
                    s.resgroup = item["resgroup"].ToString();
                if (item.ContainsKey("playername"))
                    s.playername = item["playername"].ToString();
                if (item.ContainsKey("part_name"))
                    s.part_name = item["part_name"].ToString();
                if (item.ContainsKey("part_skin"))
                    s.part_skin = item["part_skin"].ToString();
                if (item.ContainsKey("part_id"))
                    s.part_id = item["part_id"].ToString();

                s.uv.X = (int)item["X"];
                s.uv.Y = (int)item["Y"];
                s.uv.Width = (int)item["Width"];
                s.uv.Height = (int)item["Height"];
                s.povit.X = (int)item["Povit_X"];
                s.povit.Y = (int)item["Povit_Y"];
                Sprites.Add(s);
            }
        }
        public JArray ToJson()
        {
            JArray jArray = new JArray();
            foreach (var s in Sprites)
            {
                JObject json = new JObject();
                json["filename"] = s.filename;
                json["resgroup"] = s.resgroup;
                json["name"] = s.name;
                json["playername"] = s.playername;
                json["part_name"] = s.part_name;
                json["part_skin"] = s.part_skin;
                json["part_id"] = s.part_id;
                json["X"] = s.uv.X;
                json["Y"] = s.uv.Y;
                json["Width"] = s.uv.Width;
                json["Height"] = s.uv.Height;
                json["Povit_X"] = s.povit.X;
                json["Povit_Y"] = s.povit.Y;
                jArray.Add(json);
            }
            return jArray;
        }
        public List<SkinSprite> Find(string name)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.name.ToLower() == name.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
        public List<SkinSprite> FindByPlayer(string player)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.playername.ToLower() == player.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
        public List<SkinSprite> FindByPart(string part)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.part_name.ToLower() == part.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
        public List<SkinSprite> FindByPlayerAndPart(string player, string part)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.playername.ToLower() == player.ToLower() && s.part_name == part.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
    }
    //表示一个身体部位
    public class Part
    {
        public string name;//可以没有
        public string partid;
    }

    /// <summary>
    /// 表示显示的Rect
    /// </summary>
    public class ShowRect
    {
        public Part part;
        public Vector2 pos;
    }
    /// <summary>
    /// 表示功能的Rect
    /// </summary>
    public class FuncRect
    {
        public string tag;
        public Rectangle rect;
    }
    public class Frame
    {
        public bool key;
        public ShowRect[] showrects;
        public FuncRect[] funcrects;
    }
    public class Ani
    {
        public string Name;
        public int fps;
        public Frame[] frames;
    }
    public class Player
    {
        public string Name;
        public string[] Parts;
        public Ani[] Animations;
        public static Player FromJson(JObject json)
        {
            return null;
        }
        public JObject ToJson()
        {
            return null;
        }
    }
    public class PlayerList
    {
        public Dictionary<string, Player> allPlayers = new Dictionary<string, Player>();
        public void LoadFromJson(string playerpath, JArray json)
        {
            allPlayers = new Dictionary<string, Player>();
            foreach (JObject item in json)
            {
                var name = item["name"].ToString();
                var config = item["config"].ToString();
                var playerPath = System.IO.Path.Combine(playerpath, config);
                var playerjson = JObject.Parse(System.IO.File.ReadAllText(playerPath));
                allPlayers[name] = Player.FromJson(playerjson);
            }
        }
        public JArray ToJson(string playerpath)
        {
            JArray json = new JArray();
            foreach (var player in allPlayers)
            {
                JObject item = new JObject();
                item["name"] = player.Key;
                var config = player.Value.Name + ".player.json";
                item["value"] = config;
                var playerjsonfile = System.IO.Path.Combine(playerpath, config);
                System.IO.File.Delete(playerjsonfile);
                System.IO.File.WriteAllText(playerjsonfile, player.Value.ToJson().ToString(), Encoding.UTF8);
                json.Add(item);
            }
            return json;
        }
        public Player GetPlayer(string key)
        {
            return allPlayers[key];
        }
    }

}
